#define DEBUG 1		// 1 during development 0 at other times

#include <stdio.h>
#include <portaudio.h>
#include <string.h>  // For "strdup()"
#include <libintl.h>  // For "gettext()"

#ifdef WIN32
#elif __BEOS__
#elif __APPLE__
#else
# include "sys/stat.h" // for mkdir()
# include "sys/time.h" // for gettimeofday()
#endif

#include "tp_magic_api.h"  // Tux Paint "Magic" tool API header
#include "SDL_image.h"  // For IMG_Load(), to load our PNG icon

#ifndef NOSOUND
# include "tp_sound.h"

enum
{
	TOOL_TEMPLATE,
	NUM_TOOLS
};


typedef struct {
	const char *icon_filename;
	const char *name;
	const char *desc;
} toolsstru;

toolsstru tools[NUM_TOOLS] = 
{
	{
		"memo-recordbutton.png",
		gettext_noop ( "memo Record"),
		gettext_noop ( "Click to begin record, click again to stop."),
	}
};

#define MAX_PLAYQUEUE	8		// number of lookahead entries in our playback_QueueSound circular buffer
#define DEFAULT_CHANNEL	-1

#define SAMPLE_RATE  (44100)
#define FRAMES_PER_BUFFER (1024)
#define PA_SAMPLE_TYPE  paFloat32
#define SAMPLE_SILENCE  (0.0f)

PaStream *stream;
tp_sound_recording* recording;

static int recordCallback(const void *inputBuffer, void *outputBuffer,
                           unsigned long framesPerBuffer,
                           const PaStreamCallbackTimeInfo* timeInfo,
                           PaStreamCallbackFlags statusFlags,
                           void *userData ){
	
	tp_sound_recording* recording = userData;
	const SAMPLE *buffer = (const SAMPLE*)inputBuffer;

	// resize the current buffer to fit the new buffer size
	recording->samples = (SAMPLE*) realloc(recording->samples, (recording->size *  sizeof(SAMPLE)) + (framesPerBuffer * sizeof(SAMPLE)));

	// copy the full sound
	int i;
	for(i=0; i < framesPerBuffer; i++){
		recording->samples[i + recording->size] = buffer[i];	
	}

	// increase the recording size
	recording->size = recording->size + framesPerBuffer;

#ifdef DEBUG
	fprintf( stderr, ".");
#endif
	return recording->finished;
}

int memorecord(int x,int y, tp_sound_recording* recording){
	// initialize port audio needed variables
	PaStreamParameters inputParameters;
    	PaError err;
	
	inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
    	inputParameters.channelCount = 1;
    	inputParameters.sampleFormat = PA_SAMPLE_TYPE;
    	inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
    	inputParameters.hostApiSpecificStreamInfo = NULL;
    	
	// open port audio stream
    	err = Pa_OpenStream(
              &stream,
              &inputParameters,
              NULL,                  /* &outputParameters, */
              SAMPLE_RATE,
              FRAMES_PER_BUFFER,
              paClipOff,      /* we won't output out of range samples so don't bother clipping them */
              recordCallback,
              recording );

	// start port audio stream
    	err = Pa_StartStream( stream );
#ifdef DEBUG
	fprintf( stderr, "memorecord_recording\n");
#endif
	return 0;
}

/* --------------------- */
Uint32 memorecord_api_version ( void )
{
#ifdef DEBUG
	fprintf( stderr, "memorecord_api_version\n");
#endif
	return TP_MAGIC_API_VERSION;
}

int memorecord_init ( magic_api * api )
{
	tp_sound_initialize();
	PaError err;
    	err = Pa_Initialize();
	if( err != paNoError ){
		printf("PortAudioError");
	}
#ifdef DEBUG
	fprintf( stderr, "memorecord_init\n");
#endif

	return 1;
}


/* --------------------- */
int memorecord_get_tool_count ( magic_api * api )
{
#ifdef DEBUG
	fprintf( stderr, "memorecord_get_tool_count\n");
#endif
	return NUM_TOOLS;
}


/* --------------------- */
SDL_Surface * memorecord_get_icon ( magic_api * api, int which )
{
	SDL_Surface *image;
	char fname[4096];

#ifdef DEBUG
	fprintf( stderr, "memorecord_get_icon\n");
#endif

	snprintf ( fname, sizeof ( fname ), "%s/images/magic/%s",
	           api->data_directory, tools[which].icon_filename );
#ifdef DEBUG
	fprintf( stderr, "DEBUG: Loading image %s\n", fname);
#endif

	image = IMG_Load ( fname );
	if(!image) {
		fprintf(stderr, "IMG_Load( %s): %s\n", fname, IMG_GetError());
	}
	return image;
}


/* --------------------- */
char * memorecord_get_name ( magic_api * api, int which )
{
	const char * our_name_english;
	const char * our_name_localized;

#ifdef DEBUG
	fprintf( stderr, "memorecord_get_name\n");
#endif
	our_name_english = tools[which].name;
	our_name_localized = gettext ( our_name_english );
	return strdup ( our_name_localized );
}

/* --------------------- */
char * memorecord_get_description ( magic_api * api, int which, int mode )
{
	const char * our_desc_english;
	const char * our_desc_localized;

#ifdef DEBUG
	fprintf( stderr, "memorecord_get_description\n");
#endif
	our_desc_english = tools[which].desc;
	our_desc_localized = gettext ( our_desc_english );
	return strdup ( our_desc_localized );
}

/* --------------------- */
int memorecord_requires_colors ( magic_api * api, int which )
{
	return 0;	// FALSE
}

/* --------------------- */
int memorecord_modes ( magic_api * api, int which )
{
	return MODE_FULLSCREEN;
}


// Shut down
//
// explain how SDL_audioin could be patched to make Open/CloseAudioIn work
// symmetrically for the DEVDSP (Linux) driver

/* --------------------- */
void memorecord_shutdown ( magic_api * api )
{
#ifdef DEBUG
	fprintf( stderr, "memorecord_shutdown\n");
#endif
	// Terminate PortAudio
	PaError err;
	err = Pa_Terminate();
}


/* --------------------- */
void memorecord_click ( magic_api * api, int which, int mode,
                     SDL_Surface * canvas, SDL_Surface * snapshot,
                     int x, int y, SDL_Rect * update_rect )
{
#ifdef DEBUG
	fprintf( stderr, "memorecord_click\n");
#endif
	// if this is the first click
	if(recording->finished == -1){
		// check if there are recording slots available
		if(!tp_sound_recorded_sounds_full()){
			// set recording as not finished		
			recording->finished = paContinue;
			// call the recording function
			memorecord(x,y,recording);
		}
	}else{
	// if this is the second click
		// stop recording
		char fname[1024];
		recording->finished = paComplete;
		PaError err;		
		while( ( err = Pa_IsStreamActive( stream ) ) == 1 ) Pa_Sleep(100);
		Pa_CloseStream(stream);
		recording->x = x;
		recording->y = y;

		// put the recording into the available slot
		if(!tp_sound_recorded_sounds_full()){
			int result;			
			result = tp_sound_put_recording(recording);
		}
		
		// print the play icon on the screen
		static SDL_Surface *img_play;
		snprintf(fname, sizeof(fname), "%s/images/magic/play_sound.png", api->data_directory);
		img_play = IMG_Load(fname);
		update_rect->x = x-21;
		update_rect->y = y-21;
		update_rect->h = 43;
		update_rect->w = 43;	
		SDL_BlitSurface(img_play, NULL, canvas, update_rect);

		// free everything that needs to be freed
		memorecord_switchout(api,which,mode,canvas);
		memorecord_switchin(api,which,mode,canvas);
		
	}
}


/* --------------------- */
void memorecord_drag ( magic_api * api, int which, SDL_Surface * canvas,
                    SDL_Surface * snapshot, int ox, int oy, int x, int y,
                    SDL_Rect * update_rect )
{
#ifdef DEBUG
	fprintf( stderr, "memorecord_drag\n");
#endif
}


/* --------------------- */
void memorecord_release ( magic_api * api, int which,
                       SDL_Surface * canvas, SDL_Surface * snapshot,
                       int x, int y, SDL_Rect * update_rect )
{
#ifdef DEBUG
	fprintf( stderr, "memorecord_release\n");

#endif
}


/* --------------------- */
void memorecord_set_color ( magic_api * api, Uint8 r, Uint8 g, Uint8 b )
{
	// this tool uses no color
}

/* --------------------- */
void memorecord_switchin ( magic_api * api, int which, int mode, SDL_Surface * canvas )
{
#ifdef DEBUG
	fprintf( stderr, "memorecord_switchin\n");
#endif
	recording = malloc(sizeof(tp_sound_recording));
	recording->finished = -1;
	recording->size = 0;
	recording->samples = malloc(0 * sizeof(SAMPLE));
	recording->samples = 0;
	return;
}

/* --------------------- */
void memorecord_switchout ( magic_api * api, int which, int mode, SDL_Surface * canvas )
{
#ifdef DEBUG
	fprintf( stderr, "memorecord_switchout\n");
#endif
	free(recording->samples);
	free(recording);
	return;
}
#endif // NOSOUND endif
